package com.baomidou.wechat.api;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.alibaba.fastjson.JSON;
import com.baomidou.wechat.WechatCache;
import com.baomidou.wechat.common.enums.MediaType;
import com.baomidou.wechat.common.util.Attachment;
import com.baomidou.wechat.vo.ApiResult;
import com.baomidou.wechat.vo.MPAccount;
import com.baomidou.wechat.vo.api.AccessToken;
import com.baomidou.wechat.vo.api.Follower;
import com.baomidou.wechat.vo.api.FollowerList;
import com.baomidou.wechat.vo.api.Media;
import com.baomidou.wechat.vo.api.Menu;
import com.baomidou.wechat.vo.api.MenuButton;
import com.baomidou.wechat.vo.api.QRTicket;
import com.baomidou.wechat.vo.api.ServerIp;
import com.baomidou.wechat.vo.api.ShortUrl;
import com.baomidou.wechat.vo.api.Template;

/**
 * 微信API实现
 * <p>
 * 开发者文档：http://mp.weixin.qq.com/wiki/11/0e4b294685f817b95cbed85ba5e82b8f.html
 * </p>
 */
public class WechatAPIImpl extends WechatAPISupport implements WechatAPI {

	private WechatCache wechatCache;
	private MPAccount mpAct;

	protected WechatAPIImpl() {
		/* 不对外提供 */
	}

	public WechatAPIImpl(MPAccount mpAct, WechatCache wechatCache) {
		this.mpAct = mpAct;
		this.wechatCache = wechatCache;
	}

	/**
	 * 获取微信服务凭证
	 */
	public String getAccessToken() {
		String atKey = "wechat_at_" + mpAct.getAppId();
		AccessToken at = (AccessToken) wechatCache.get(atKey);
		if (at == null) {
			try {
				at = refreshAccessToken();
				if (at != null && at.isOK()) {
					wechatCache.set(atKey, at, at.getExpires_in());
				}
			} catch (Exception e) {
				logger.error("getAccessToken error.", e);
			} finally {
				if (at == null) {
					return null;
				}
			}
		}
		return at.getAccess_token();
	}

	/**
	 * 强制刷新微信服务凭证
	 * <p>
	 * 尝试3次获取票据
	 * </p>
	 */
	private synchronized AccessToken refreshAccessToken() throws Exception {
		for (int i = 0; i < 3; i++) {
			AccessToken at = httpGet(AccessToken.class, API_ACCESS_TOKEN, mpAct.getAppId(), mpAct.getAppSecret());
			if (at != null) {
				return at;
			}
		}
		return null;
	}

	/**
	 * 获取微信服务IP地址
	 */
	public List<String> getServerIps() {
		ServerIp si = httpGet(ServerIp.class, API_SERVER_IPS, getAccessToken());
		return si.getIp_list();
	}

	public String getShortUrl(String longUrl) {
		StringBuffer json = new StringBuffer("{");
		json.append("\"action\":\"long2short\",");
		json.append("\"long_url\":\"").append(longUrl).append("\",");
		ShortUrl shortUrl = httpPostJson(ShortUrl.class, json.toString(), API_SHORT_URL, getAccessToken());
		if (shortUrl != null && shortUrl.isOK()) {
			return shortUrl.getShort_url();
		}
		return null;
	}

	public String getJSTicket() {
		// TODO Auto-generated method stub
		return null;
	}

	public long sendTemplateMsg(String openId, String tmlId, String topColor, String url, Template... tmls) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public boolean updateRemark(String openId, String remark) {
		Map<String, String> data = new HashMap<String, String>();
		data.put("openid", openId);
		data.put("remark", remark);
		ApiResult ar = httpPost(ApiResult.class, data, API_USER_REMARK, getAccessToken());
		return retBool(ar);
	}

	@Override
	public Follower getFollower(String openId, String lang) {
		return httpGet(Follower.class, API_USER_INFO, getAccessToken(), openId, lang);
	}

	@Override
	public FollowerList getFollowerList(String nextOpenId) {
		return httpGet(FollowerList.class, API_USER_LIST, getAccessToken(), nextOpenId);
	}

	@Override
	public List<Follower> getFollowers() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Media upMedia(MediaType mediaType, File mediaFile) {
		return httpPostFile(mediaFile, API_UPLOAD_MEDIA, getAccessToken(), mediaType.key());
	}

	@Override
	public Attachment dlMedia(String mediaId) {
		return httpDownload(API_GET_MEDIA, getAccessToken(), mediaId);
	}

	@Override
	public QRTicket createQR(Object sceneId, int expireSeconds) {
		StringBuffer json = new StringBuffer("{");
		String action_name = "\"QR_SCENE\"";
		String scene = "\"scene_id\": " + sceneId;
		if (expireSeconds > 0) {
			/*
			 * 临时二维码
			 */
			json.append("\"expire_seconds\":").append(expireSeconds).append(",");
		} else if (sceneId instanceof Number) {
			/*
			 * 永久二维码
			 */
			action_name = "\"QR_LIMIT_SCENE\"";
		} else {
			/*
			 * 永久字符串二维码
			 */
			action_name = "\"QR_LIMIT_STR_SCENE\"";
			scene = "\"scene_str\": \"" + sceneId + "\"";
		}
		json.append("\"action_name\":").append(action_name).append(",");
		json.append("\"action_info\":{\"scene\": {").append(scene).append("}}}");
		return httpPostJson(QRTicket.class, json.toString(), API_CREATE_QRCODE, getAccessToken());
	}

	@Override
	public List<Menu> getMenu() {
		MenuButton menuButton = httpGet(MenuButton.class, API_QUERY_MENU, getAccessToken());
		return menuButton != null ? menuButton.getButton() : null;
	}

	@Override
	public boolean createMenu(MenuButton menuButton) {
		String json = JSON.toJSONString(menuButton);
		ApiResult ar = httpPostJson(ApiResult.class, json, API_CREATE_MENU, getAccessToken());
		return retBool(ar);
	}

	@Override
	public boolean delMenu() {
		ApiResult ar = httpGet(ApiResult.class, API_DEL_MENU, getAccessToken());
		return retBool(ar);
	}

	/**
	 * 判断 API请求返回结果是否正确
	 * 
	 * @param ar
	 *            API请求返回结果 {@link ApiResult}
	 * @return
	 */
	private boolean retBool(ApiResult ar) {
		return ar != null ? ar.isOK() : false;
	}

}
